package com.ywk.base.common.office.excel.importExcel;


import com.ywk.base.common.office.excel.ExcelField;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jsoup.helper.StringUtil;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;

/**
 * 导入Excel文件
 * @author binzec
 */
public class ImportExcel {

	/**
	 * 常规导入
	 * @param file
	 * @param request
	 * @throws IOException
	 */
	public void generalImport(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
		ImportExcel ex=new ImportExcel(file.getOriginalFilename(),file.getInputStream(),0,0);

		System.out.println("开始行="+ex.getDataRowNum()+"--结束行="+ex.getLastDataRowNum());
		for (int i = ex.getDataRowNum()-1; i <= ex.getLastDataRowNum(); i++) {
			Row row = ex.getRow(i);
			String name =(ex.getCellValue(row, 1)!=null?ex.getCellValue(row, 1).toString():"");//项目名称
			String code =ex.getCellValue(row, 2)!=null?ex.getCellValue(row,2).toString():"".trim();//项目编号
		}
	}


	/**
	 * 举个例子，从前端传来一个EXCEL文件，我们从MultipartHttpServletRequest里获取出来
	 */
	@RequestMapping("doImport")
	public void doImport(MultipartHttpServletRequest req) {
		try {
			// 假设前端只传一个文件，则只需要迭代一次获取，得到该文件对象
			MultipartFile file = req.getFile(req.getFileNames().next());
			// 假设EXCEL文件是标准的格式，即数据在第一个工作表的第三行开始
			List<Demo> list = new ImportExcel(file.getOriginalFilename(), file.getInputStream(), 0, 0).getDataList(Demo.class);
			for (Demo demo : list) {
				System.out.println(demo);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 工作薄对象
	 */
	private Workbook wb;
	
	/**
	 * 工作表对象
	 */
	private Sheet sheet;
	
	/**
	 * 数据行号
	 */
	private int dataRow = 0;
	/**
	 * 构造函数
	 * @param fileName		导入excel文件名
	 * @param is			导入excel输入流
	 * @param sheetIndex	工作表序号（第一个为0）
	 * @param headerNum		标题行号（第二行为1）（因为要从标题行下一行开始读取数据）
	 */
	public ImportExcel(String fileName, InputStream is, int sheetIndex, int headerNum) {
		// fileName不能为空；且必须是xls或xlsx格式的文件
		try {
			if (StringUtil.isBlank(fileName)) {
				throw new RuntimeException("导入文档为空!");
			} else if (fileName.toLowerCase().endsWith("xls")) {
				this.wb = new HSSFWorkbook(is);
			} else if (fileName.toLowerCase().endsWith("xlsx")) {
				this.wb = new XSSFWorkbook(is);
			} else {
				throw new RuntimeException("文档格式不正确!");
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("加载excel出错!");
		}
		// 看是否有该工作表编号，有就加载该表
		if (this.wb.getNumberOfSheets() < sheetIndex) {
			throw new RuntimeException("文档中没有工作表!");
		}
		this.sheet = this.wb.getSheetAt(sheetIndex);
		// 标题行下一行即为数据行第一行
		this.dataRow = headerNum + 1;
	}
	
	/**
	 * 获取最后一个数据行号
	 */
	public int getLastDataRowNum() {
		return this.sheet.getLastRowNum();
	}
	
	/**
	 * 获取最后一个数据列号
	 */
	public int getLastCellNum() {
		return this.sheet.getRow(dataRow).getLastCellNum();
	}
	
	/**
	 * 获取单元格值
	 * @param row 		获取的行
	 * @param column 	获取单元格列号
	 * @return 			单元格值
	 */
	public Object getCellValue(Row row, int column) {
		Object val = "";
		try {
			Cell cell = row.getCell(column);
			if (cell != null) {
				if (cell.getCellType() == CellType.NUMERIC) {
					val = cell.getNumericCellValue();
				} else if (cell.getCellType() == CellType.STRING) {
					val = cell.getStringCellValue();
				} else if (cell.getCellType() == CellType.FORMULA) {
					val = cell.getCellFormula();
				} else if (cell.getCellType() == CellType.BOOLEAN) {
					val = cell.getBooleanCellValue();
				} else if (cell.getCellType() == CellType.ERROR) {
					val = cell.getErrorCellValue();
				}
			}
		} catch (Exception e) {
			return val;
		}
		return val;
	}


	/**
	 * 获取行对象
	 * @param rownum
	 * @return
	 */
	public Row getRow(int rownum){
		return this.sheet.getRow(rownum);
	}

	/**
	 * 获取数据行号
	 * @return
	 */
	public int getDataRowNum(){
		return dataRow+1;
	}
	/**
	 * 获取导入数据列表
	 * @param clazz 导入对象类型
	 * @param groups 导入分组
	 */
	public <E> List<E> getDataList(Class<E> clazz, String... groups) {
		// 注解集合（Object[]{ ExcelField, Field }）
		List<Object[]> annotationList = new ArrayList<Object[]>();
		// 反射暴力取出该实体类的全部字段
		Field[] fs = clazz.getDeclaredFields();
		for (Field f : fs) {
			f.setAccessible(true);
			// 取出每一个字段上面的ExcelField注解
			ExcelField ef = f.getAnnotation(ExcelField.class);
			// 取得出来，且注解的type属性是0或1（0：导出导入；2：仅导入），则通过判断
			if (ef != null && (ef.type() == 0 || ef.type() == 2)) {
				// 如果有规定分组，则把符合分组的字段判断出来
				if (groups != null && groups.length > 0) {
					// 符合分组的，则把该字段加入到集合中（下面两个for循环，原理就是两个数组的比较，只要双方存在相同元素就行）
					boolean inGroup = false;
					for (String g : groups) {
						if (inGroup) {
							break;
						}
						for (String efg : ef.groups()) {
							if (g.equals(efg)) {
								inGroup = true;
								annotationList.add(new Object[] { ef, f });
								break;
							}
						}
					}
					// 没有分组规则，则直接把该字段加入到集合中
				} else {
					annotationList.add(new Object[] { ef, f });
				}
			}
		}
		// 让字段根据注解中的sort属性从小到大排序下
		Collections.sort(annotationList, new Comparator<Object[]>() {
			public int compare(Object[] o1, Object[] o2) {
				return new Integer(((ExcelField) o1[0]).sort()).compareTo(new Integer(((ExcelField) o2[0]).sort()));
			};
		});
		// 新建一个存放数据的集合
		List<E> dataList = new ArrayList<E>();
		// 逐行遍历EXCEL表格
		for (int i = dataRow; i <= this.getLastDataRowNum(); i++) {
			try {
				// 新建这个类的实例，待会儿可以封装数据，一个实体类就是一行数据
				E e = (E) clazz.newInstance();
				// 取出行对象
				Row row = this.sheet.getRow(i);
				// 从第一列开始读取
				int column = 0;
				// 循环注解集合，我们已经约定注解集合顺序与EXCEL列顺序是一致的了
				for (Object[] os : annotationList) {
					// 取出字段反射对象
					Field field = ((Field) os[1]);
					// 根据行对象和列编号获取单元格对应的值
					Object val = getCellValue(row, column++);
					// 如果值为空，就跳过不管
					if (!StringUtils.isEmpty(val)) {
						// 取出字段对应的类型，将val值转成对应的类型存放进来
						Class<?> valType = field.getType();
						if (valType == String.class) {
							String s = String.valueOf(val.toString());
							if (val instanceof Double) {
								NumberFormat format = DecimalFormat.getInstance();
								format.setMaximumFractionDigits(10);
								format.setGroupingUsed(false);
								val = format.format(val);
							}
							if (org.apache.commons.lang3.StringUtils.endsWith(s, ".0")) {
								val = org.apache.commons.lang3.StringUtils.substringBefore(s, ".0");
							} else {
								val = String.valueOf(val.toString());
							}
						} else if (valType == Integer.class) {
							val = Double.valueOf(val.toString()).intValue();
						} else if (valType == Long.class) {
							val = Double.valueOf(val.toString()).longValue();
						} else if (valType == Double.class) {
							val = Double.valueOf(val.toString());
						} else if (valType == Float.class) {
							val = Float.valueOf(val.toString());
						} else if (valType == Date.class || valType == java.sql.Date.class) {
							val = DateUtils.parseDate(val.toString());
						} else if (valType == BigDecimal.class) {
							val = new BigDecimal(val.toString());
						} else {
							val = null;
						}
						// 把获取到的值暴力反射存入实体类里
						field.set(e, val);
					}
				}
				dataList.add(e);
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
		return dataList;
	}
}

/**
 * 举例子方法用到的实体类
 */
class Demo {
	@ExcelField(title = "第1列", sort = 0)
	private String id;
	@ExcelField(title = "第2列", sort = 1)
	private String childid;
	@ExcelField(title = "第3列", sort = 2)
	private String mainid;
	public Demo() {
		super();
	}
	public Demo(String id, String childid, String mainid) {
		super();
		this.id = id;
		this.childid = childid;
		this.mainid = mainid;
	}
	@Override
	public String toString() {
		return "Demo [id=" + id + ", childid=" + childid + ", mainid=" + mainid + "]";
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getChildid() {
		return childid;
	}
	public void setChildid(String childid) {
		this.childid = childid;
	}
	public String getMainid() {
		return mainid;
	}
	public void setMainid(String mainid) {
		this.mainid = mainid;
	}
	
	
	
}